import asyncio
import json
import os
from typing import Optional, List
from aiortc import RTCIceCandidate, RTCPeerConnection, RTCSessionDescription, VideoStreamTrack
from fastapi import APIRouter, Request, Depends, Cookie, HTTPException, Query, WebSocket
from fastapi.responses import HTMLResponse, FileResponse, RedirectResponse
from sqlalchemy.orm import Session
from sqlalchemy.orm import joinedload
from sqlalchemy import or_, and_, func
from database import get_db
from models import Alarm
from routers.realtime import get_local_ip
from utils import save_image, validate_session
from core.logger import app_logger as logger
from datetime import datetime, timedelta
from templates import templates
from pydantic import BaseModel
import subprocess  # 用于执行FFmpeg命令
import uuid  # 生成唯一会话ID
import shutil  # 清理临时目录
import re  # 正则表达式
from aiortc.contrib.media import MediaPlayer
from aiortc.contrib.media import MediaRecorder


# 创建路由实例
router = APIRouter()

# 图片存储目录
IMAGE_STORAGE_DIR = "alarm_images"
os.makedirs(IMAGE_STORAGE_DIR, exist_ok=True)

# 清理旧转码会话的定时器
LAST_CLEANUP_TIME = datetime.now()

class DeleteAlertsRequest(BaseModel):
    alert_ids: List[int]

LOCAL_IP = get_local_ip()
ICE_CANDIDATE = f"{LOCAL_IP}"

@router.get("/alerts", response_class=HTMLResponse)
async def alerts_page(
    request: Request,
    SessionId: Optional[str] = Cookie(None),
    UserName: Optional[str] = Cookie(None),
    page: int = 1,
    page_size: int = 10,
    search: Optional[str] = Query(None),
    start_date: Optional[str] = Query(None),
    end_date: Optional[str] = Query(None),
    db: Session = Depends(get_db)
):
    if not SessionId or not UserName or not validate_session(SessionId, UserName):
        return RedirectResponse(url="/")
    
    # 构建基础查询 - 只查询未删除的告警
    query = db.query(Alarm).filter(Alarm.DeadTime.is_(None))
    
    # 添加搜索条件
    if search:
        query = query.filter(or_(
            Alarm.Summary.ilike(f"%{search}%"),
            Alarm.BoardIp.ilike(f"%{search}%"),
            Alarm.TaskDesc.ilike(f"%{search}%"),
            Alarm.ResultDescription.ilike(f"%{search}%")
        ))
    
    # 添加时间范围筛选
    if start_date or end_date:
        try:
            # 处理开始日期
            if start_date:
                start_datetime = datetime.strptime(start_date, "%Y-%m-%d")
                # 包含整个开始日
                start_datetime = start_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
            else:
                # 如果没有开始日期，使用30天前作为默认
                start_datetime = datetime.now() - timedelta(days=30)
            
            # 处理结束日期
            if end_date:
                end_datetime = datetime.strptime(end_date, "%Y-%m-%d")
                # 包含整个结束日
                end_datetime = end_datetime.replace(hour=23, minute=59, second=59, microsecond=999999)
            else:
                # 如果没有结束日期，使用当前时间
                end_datetime = datetime.now()
            
            # 添加时间范围过滤
            query = query.filter(Alarm.CreateTime.between(start_datetime, end_datetime))
        except ValueError as e:
            logger.warning(f"日期格式错误: {str(e)}")
            # 日期格式错误时忽略时间筛选
    
    total_alarms = query.count()
    total_pages = (total_alarms + page_size - 1) // page_size
    
    if page < 1:
        page = 1
    elif page > total_pages and total_pages > 0:
        page = total_pages
        
    offset = (page - 1) * page_size
    alarms = query.options(joinedload(Alarm.passage)).order_by(Alarm.CreateTime.desc()).limit(page_size).offset(offset).all()
    
    # 构建查询参数字符串用于分页和页面大小
    query_params = f"&page_size={page_size}"
    if search:
        query_params += f"&search={search}"
    if start_date:
        query_params += f"&start_date={start_date}"
    if end_date:
        query_params += f"&end_date={end_date}"
    
    return templates.TemplateResponse("alerts.html", {
        "request": request,
        "UserName": UserName,
        "alarms": [alarm.to_dict() for alarm in alarms],
        "page": page,
        "page_size": page_size,
        "total_pages": total_pages,
        "total_alarms": total_alarms,
        "search_query": search or "",
        "start_date": start_date or "",
        "end_date": end_date or "",
        "query_params": query_params
    })

@router.post("/api/delete-alerts")
async def delete_alerts(
    request: DeleteAlertsRequest,  # 使用定义好的模型
    db: Session = Depends(get_db)
):
    try:
        # 更新deadtime为当前时间
        db.query(Alarm).filter(Alarm.AlarmId.in_(request.alert_ids)).update(
            {"DeadTime": datetime.now()},
            synchronize_session=False
        )
        db.commit()
        return {"status": "success", "message": f"已成功删除 {len(request.alert_ids)} 条告警记录"}
    except Exception as e:
        db.rollback()
        logger.error(f"删除告警时出错: {str(e)}", exc_info=True)
        raise HTTPException(500, f"服务器错误: {str(e)}")

@router.post("/api/receive-alert")
async def receive_alert(
    request: Request,
    db: Session = Depends(get_db)
):
    
    try:
        alarm_data = await request.json()
        #logger.info(f'收到报警信息: {alarm_data}')
        required_fields = ["BoardIp", "BoardId",  "Result", "ImageData"]
        for field in required_fields:
            if field not in alarm_data or not alarm_data[field]:
                raise HTTPException(400, f"缺少必填字段: {field}")
                
        image_path = save_image(IMAGE_STORAGE_DIR,alarm_data["ImageData"])
        
        people_number = None
        for prop in alarm_data["Result"].get("Properties", []):
            if prop.get("property") == "people_number":
                people_number = prop.get("value")
                break
                
        new_alarm = Alarm(
            BoardIp=alarm_data["BoardIp"],
            BoardId=alarm_data["BoardId"],
            DataId=alarm_data.get("DataId"),
            # AlarmId=alarm_data["AlarmId"],
            Type=alarm_data.get("Type"),
            Summary=alarm_data.get("Summary"),
            Time=alarm_data.get("Time"),
            TimeStamp=alarm_data.get("TimeStamp"),
            # UniqueId=alarm_data.get("UniqueId"),
            TaskDesc=alarm_data.get("TaskDesc"),
            TaskSession=alarm_data.get("TaskSession"),
            ResultType=alarm_data["Result"].get("Type"),
            ResultDescription=alarm_data["Result"].get("Description"),
            PeopleNumber=people_number,
            ImagePath=image_path,
            PassageId=alarm_data["Media"].get("MediaName")
        )
        
        db.add(new_alarm)
        db.commit()
        db.refresh(new_alarm)
        
        return {
            "status": "success",
            "message": "告警已接收并存储",
            "alert_id": new_alarm.AlarmId,
            "alert": new_alarm.to_dict()
        }
        
    except Exception as e:
        db.rollback()
        logger.error(f"存储告警时出错: {str(e)}", exc_info=True)
        raise HTTPException(500, f"服务器错误: {str(e)}")

@router.get("/api/alerts")
async def get_alerts(
    db: Session = Depends(get_db), 
    limit: int = 100, 
    offset: int = 0
):
    alarms = db.query(Alarm).filter(Alarm.DeadTime.is_(None)).order_by(Alarm.CreateTime.desc()).limit(limit).offset(offset).all()
    return {
        "status": "success", 
        "count": len(alarms), 
        "alarms": [alarm.to_dict() for alarm in alarms]
    }

@router.get("/api/alerts/image/{image_path:path}")
async def get_alert_image(image_path: str):
    full_path = os.path.join(IMAGE_STORAGE_DIR, image_path)
    if not os.path.exists(full_path):
        raise HTTPException(404, "图片不存在")
    return FileResponse(full_path, media_type="image/jpeg")

@router.websocket("/ws/playback/{alarm_id}")
async def playback_websocket(
    websocket: WebSocket, 
    alarm_id: int,
    db: Session = Depends(get_db)
):
    await websocket.accept()
    logger.info(f"告警回放WebSocket连接已建立: {alarm_id}")
    
    # 查询告警记录
    alarm = db.query(Alarm).filter(Alarm.AlarmId == alarm_id).first()
    if not alarm:
        await websocket.close(code=4001, reason="告警记录不存在")
        return
    
    # 生成回放URL
    try:
        rtsp_url = get_playback_url(alarm, db)  # 传递db参数
        logger.info(f"生成的RTSP回放URL: {rtsp_url}")
    except Exception as e:
        logger.error(f"生成回放URL失败: {str(e)}")
        await websocket.close(code=4002, reason=f"生成回放URL失败: {str(e)}")
        return
    
    pc = None
    player = None
    
    try:
        # 发送ICE候选信息
        await websocket.send_text(json.dumps({
            "type": "ice_info",
            "ice_candidate": ICE_CANDIDATE
        }))
        
        # 创建MediaPlayer实例
        player = MediaPlayer(
            rtsp_url,
            format="rtsp",
            options={
                "rtsp_transport": "tcp",  # 回放建议使用TCP更稳定
                "fflags": "nobuffer",
                "tune": "zerolatency",
                "framedrop": "1",
                "timeout": "5000000"  # 5秒超时
            }
        )
        
        # 检查视频轨道是否可用
        if not player.video:
            logger.error("无法获取视频轨道")
            await websocket.send_text(json.dumps({
                "type": "error",
                "message": "无法获取视频轨道"
            }))
            return
        
        pc = RTCPeerConnection()
        
        # 创建视频轨道
        if player.video:
            pc.addTrack(player.video)
        else:
            logger.error("无法获取视频轨道")
            await websocket.send_text(json.dumps({
                "type": "error",
                "message": "无法获取视频轨道"
            }))
            return
        
        # 处理ICE候选
        @pc.on("icecandidate")
        def on_icecandidate(candidate):
            if candidate:
                logger.debug(f"生成的本地ICE候选: {candidate.candidate}")
                asyncio.run(websocket.send_text(json.dumps({
                    "type": "candidate",
                    "candidate": {
                        "candidate": candidate.candidate,
                        "sdpMid": candidate.sdpMid,
                        "sdpMLineIndex": candidate.sdpMLineIndex
                    }
                })))
        
        # 处理连接状态变化
        @pc.on("connectionstatechange")
        async def on_connectionstatechange():
            state = pc.connectionState
            logger.info(f"WebRTC连接状态变化: {state}")
            if state == "failed":
                await websocket.send_text(json.dumps({
                    "type": "error",
                    "message": "WebRTC连接失败"
                }))
        
        @pc.on("track")
        async def on_track(track):
            logger.info(f"接收到轨道: {track.kind}")
            if track.kind == "video":
                while True:
                    try:
                        frame = await track.recv()
                        # 检查帧是否有效
                    except Exception as e:
                        logger.info("视频流结束")
                        break

        # 处理WebSocket消息
        while True:
            data = await websocket.receive_text()
            message = json.loads(data)
            logger.debug(f"收到WebSocket消息: {message}")
            
            if message.get("type") == "offer":
                try:
                    offer = RTCSessionDescription(
                        sdp=message["offer"]["sdp"],
                        type=message["offer"]["type"]
                    )
                    await pc.setRemoteDescription(offer)
                    
                    # 创建应答
                    answer = await pc.createAnswer()
                    
                    # SDP格式修正
                    sdp = answer.sdp
                    sdp = sdp.replace("a=msid-semantic:WMS *\r\n", "")
                    sdp += "a=direction:sendrecv\r\n"
                    answer = RTCSessionDescription(sdp=sdp, type=answer.type)
                    
                    await pc.setLocalDescription(answer)
                    
                    await websocket.send_text(json.dumps({
                        "type": "answer",
                        "answer": {
                            "sdp": pc.localDescription.sdp,
                            "type": pc.localDescription.type
                        }
                    }))
                    logger.info("已发送Answer")
                    
                except Exception as e:
                    logger.error(f"处理Offer失败: {str(e)}", exc_info=True)
                    await websocket.send_text(json.dumps({
                        "type": "error",
                        "message": f"处理Offer失败: {str(e)}"
                    }))
            
            elif message.get("type") == "candidate" and pc:
                try:
                    candidate_data = message["candidate"]
                    if not candidate_data.get("candidate"):
                        continue
                        
                    # 解析候选字符串
                    parts = candidate_data["candidate"].split()
                    foundation = parts[0]
                    component = int(parts[1])
                    protocol = parts[2].lower()
                    priority = int(parts[3])
                    ip = parts[4]
                    port = int(parts[5])
                    typ = parts[7]
                    
                    # 创建候选对象
                    candidate = RTCIceCandidate(
                        foundation=foundation,
                        component=component,
                        protocol=protocol,
                        priority=priority,
                        ip=ip,
                        port=port,
                        type=typ,
                        sdpMid=candidate_data["sdpMid"],
                        sdpMLineIndex=candidate_data["sdpMLineIndex"]
                    )
                    
                    await pc.addIceCandidate(candidate)
                    logger.debug("成功添加ICE候选")
                except Exception as e:
                    logger.error(f"添加ICE候选失败: {str(e)}")
                    logger.debug(f"候选数据: {candidate_data}")
    
    except Exception as e:
        logger.error(f"告警回放错误: {str(e)}", exc_info=True)
        await websocket.send_text(json.dumps({
            "type": "error",
            "message": f"视频流处理错误: {str(e)}"
        }))
    finally:
        logger.info("正在清理回放资源...")
        try:
            if pc:
                await pc.close()
            if player:
                player.video.stop()
        except Exception as e:
            logger.error(f"清理资源时出错: {str(e)}")
        await websocket.close()
        logger.info("回放连接已关闭")


def get_playback_url(alarm: Alarm, db: Session):
    """
    获取告警回放URL
    
    参数:
        alarm: 告警对象
        db: 数据库会话
    """
    try:
        # 直接调用Alarm模型的PlaybackURL方法
        playback_url = alarm.PlaybackURL
        logger.info(f"生成的RTSP URL: {playback_url}")
        return playback_url
    except Exception as e:
        logger.error(f"获取回放URL失败: {str(e)}")
        raise